package chart;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Collections;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.TextAnchor;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;

import util.Constants;

import db.DatabaseManager;
import db.entity.TaperMap;
import db.entity.WCSDataInterface;

public class ParetoChartPanel extends ChartPanel  {

	public static final int GRAPH_TTV = 0;
	public static final int GRAPH_STIR = 1;
	public static final int GRAPH_TIR = 2;
	public static final int GRAPH_TAPERSPC = 3;
	public static final int GRAPH_REMOVAL = 4;
	
	private static final long serialVersionUID = 1L;

	DefaultCategoryDataset dataset = new DefaultCategoryDataset();
	
	private CategoryPlot paretoPlot = null;
	private JFreeChart paretoChart = null;
	
	public ParetoChartPanel()
	{
		super(null);
		
		paretoChart = ChartFactory.createBarChart("Pareto", "Polisher Arm", "Average", dataset, PlotOrientation.VERTICAL, false, true, false);
		paretoChart.setBackgroundPaint(Color.white);
		
		paretoPlot = paretoChart.getCategoryPlot();
		paretoPlot.setBackgroundPaint(Color.lightGray);
		paretoPlot.setDomainGridlinePaint(Color.white);
		paretoPlot.setRangeGridlinePaint(Color.white);
		
		NumberAxis rangeAxis = (NumberAxis)paretoPlot.getRangeAxis();
		rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
		
		BarRenderer paretoRenderer = (BarRenderer)paretoPlot.getRenderer();
		paretoRenderer.setDrawBarOutline(false);
		paretoRenderer.setItemMargin(0.1D);
		
		GradientPaint gp0 = new GradientPaint(0.0F, 0.0F, Color.blue, 0.0F, 0.0F, Color.lightGray);
		
		paretoRenderer.setSeriesPaint(0, gp0);
		paretoRenderer.setSeriesPaint(1, gp0);
		paretoRenderer.setSeriesPaint(2, gp0);
		paretoRenderer.setSeriesPaint(3, gp0);
		paretoRenderer.setSeriesPaint(4, gp0);
		paretoRenderer.setSeriesPaint(5, gp0);
		paretoRenderer.setSeriesPaint(6, gp0);

		paretoRenderer.setBaseItemLabelGenerator(new LabelGenerator());
		paretoRenderer.setBaseItemLabelsVisible(true);
		ItemLabelPosition p = new ItemLabelPosition(ItemLabelAnchor.INSIDE12, TextAnchor.CENTER_RIGHT, TextAnchor.CENTER_RIGHT, -1.570796326794897D);
	
		paretoRenderer.setBasePositiveItemLabelPosition(p);
		
		ItemLabelPosition p2 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.CENTER_LEFT, TextAnchor.CENTER_LEFT, -1.570796326794897D);
		
		paretoRenderer.setPositiveItemLabelPositionFallback(p2);

		this.setChart(paretoChart);
		this.setDisplayToolTips(true);
	}
	
	public void loadData(int graphOption, String title, List<WCSDataInterface> sList)
	{
		dataset.clear();
		
		ArrayList<AverageEntry> sItemAvg = new ArrayList<AverageEntry>();
		
		String stationID;
		Double average;
		int stationNo, armNo, arrayIndex;
		for(int i =0; i<14; i++)
			sItemAvg.add(new AverageEntry());
		
		for(WCSDataInterface sItem : sList)
		{
			// Get the stationID in form of "1L", "2R", "3L", ...
			String dcEl01 = sItem.getDCElement();
			String dcEl02="";
			switch(graphOption)
			{
			case GRAPH_TTV: dcEl02 = dcEl01.replace("TTV", "TP");  break;
			case GRAPH_TIR: dcEl02 = dcEl01.replace("TIR", "TP"); break;
			case GRAPH_STIR: dcEl02 = dcEl01.replace("STIR", "TP");  break;
			case GRAPH_REMOVAL: dcEl02 = dcEl01.replace("PREMDS", "TP");  break;
			case GRAPH_TAPERSPC: dcEl02 = dcEl01; break;
			}
			stationID = mapDCElement(dcEl02);
			
			// shortcut to find the correct array slot for average value.
			stationNo = Integer.parseInt(stationID.substring(0,1));
			armNo = stationID.charAt(1)== 'L' ? 1 : 2;			
			arrayIndex = (stationNo -1)*2 + (armNo -1);
			
			average = (sItem.getValue1() + sItem.getValue2() + sItem.getValue3() + sItem.getValue4())/4;
			
			if (sItemAvg.get(arrayIndex).armID.equals(""))
				sItemAvg.get(arrayIndex).armID = "A"+stationID;
			
			sItemAvg.get(arrayIndex).average += average;
			sItemAvg.get(arrayIndex).entryCount++;
		}
		
		
		Collections.sort((List<AverageEntry>)sItemAvg, new AvgEntryComparator());
		for(int i=0; i<14; i++)
		{
			double finalAverage = sItemAvg.get(i).average / sItemAvg.size();
			dataset.setValue(finalAverage, sItemAvg.get(i).entryCount+"", sItemAvg.get(i).armID);
		}
		
		paretoChart.setTitle(title);
		this.restoreAutoBounds();
	}
	
	ArrayList<String> mapList = null;
	/*
	 * This ArrayList<String> mapList will contains all taper mapping name in such:
	 *	 Index	Station/Arm
	 *	  0		 1L
	 *	  1		 1R
	 *	  2		 2L
	 *	  3		 2R
	 *	  4		 3L
	 *	  5		 3R
	 *	  6		 4L
	 *	  7		 4R
	 *	  8		 5L
	 *	  9		 5R
	 *	 10		 6L
	 *	 11		 6R
	 *	 12		 7L
	 *	 13		 7R
	 */
	private String mapDCElement(String DCElement)
	{
		if(mapList == null)
		{
			mapList = new ArrayList<String>(14);
			for(int i=0; i<14; i++)
				mapList.add("");
			
			List<TaperMap>taperMapList = new DatabaseManager().listTaperMap();
			int index=0;
			for(TaperMap mapItem : taperMapList)
			{
				index = Integer.parseInt(mapItem.getStationName());
				if(index > 7)
					continue;
				index = (index -1) * 2;
				mapList.set(index, mapItem.getLeftTaper());
				mapList.set(index+1, mapItem.getRightTaper());				
			}
		}
				
		int index = mapList.indexOf(DCElement);
		
		int stationNo = (index / 2) + 1;
		char armNo = index%2 == 0? 'L': 'R';
		
		return stationNo+""+armNo;
	}

	private class AverageEntry
	{
		public String armID;
		public double average;
		public int entryCount;
		public AverageEntry()
		{
			armID = "";
			average = 0;
			entryCount =0;
		}
	}
	
	private class AvgEntryComparator implements Comparator
	{
		@Override
		public int compare(Object arg0, Object arg1) {
			AverageEntry target, item;
			if(arg0 instanceof AverageEntry && arg1 instanceof AverageEntry)
			{
				item = (AverageEntry)arg0;
				target = (AverageEntry)arg1;
			
				if(item.average == target.average)
					return 0;
				else if(item.average > target.average)
					return -1;
				else 
					return 1;	
			}
			else
				return -1;		
		}
	}
	
	static class LabelGenerator extends StandardCategoryItemLabelGenerator
	{
		private static final long serialVersionUID = 1L;
		public String generateLabel(CategoryDataset dataset, int series, int category)
		{
			DecimalFormat df = new DecimalFormat("#.##");

			return df.format(dataset.getValue(series, category));
		}
	}

	
	public void drawChart(Graphics2D g2, Rectangle2D r2D)
	{
		paretoChart.draw(g2, r2D);
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void main(String[] args) {
		db.DatabaseManager dm = new db.DatabaseManager();
		DateFormat dtFmt = new java.text.SimpleDateFormat();
		
		List sList;
		try {
			sList = dm.listSTIR(1, dtFmt.parse("12/17/2010 0:0 PM, PDT"), dtFmt.parse("12/20/2010 21:00 PM, PDT"));
			System.out.println("List: "+sList.size());
			ParetoChartPanel pcPnl = new ParetoChartPanel();
			pcPnl.loadData(TendChartPanel.GRAPH_STIR, "AVE STIR Pareto", ((List<WCSDataInterface>)sList));
			javax.swing.JFrame window = new javax.swing.JFrame("Testing Graph");
			window.setLayout(new FlowLayout());
			window.getContentPane().add(pcPnl);
	        window.setSize(800, 500);
	        window.setLocation(50, 50);
			window.setVisible(true);
			
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}
}
